#include "qproperty.h"

#include "qobjectproperty.h"

#include "../../lib/shared/quixml.h"
#include "../../lib/shared/qproject.h"
#include "../../include/abstractcore.h"


#include <QRect>
#include <QStyleOption>
#include <QPixmap>
#include <QStyle>
#include <QApplication>
#include <QPainter>
#include <QFont>
#include <QMessageBox>
#include <QMetaProperty>
#include <QMetaEnum>
#include <QCursor>
#include <QDateTime>

QProperty::QProperty(const QString &name, QProperty *parent):
    m_name(name),
    m_enabled(true),
    m_modified(false),
    m_reset(true),
    m_parent(parent),
    m_xmlProperty(new XMLProperty),
    m_needSave(false)
{
    if(m_parent!=NULL)
    {
        m_parent->m_children.append(this);
    }
    m_xmlProperty->setPropertyName(name);
}

QProperty::~QProperty()
{
    while(m_children.size()>0)
    {
        delete m_children.first();
        m_children.removeFirst();
    }
    delete m_xmlProperty;
}

QList<QProperty*> QProperty::children()
{
    return m_children;
}

void QProperty::setValue(const QVariant &value)
{
    m_xmlProperty->setValue(m_value);
    if(m_value!=value)
    {
        m_value=value;
        valueChanged();
    }
}

void QProperty::setEnabled(bool enabled)
{
    m_enabled=enabled;
}

void QProperty::setModified(bool modified)
{
    m_modified=modified;
    if(m_modified)
    {
        if(m_parent!=NULL)
        {
            m_parent->setModified(m_modified);
        }
    }
}

QString QProperty::name()
{
    return m_name;
}

QString QProperty::valueText()
{
    return m_value.toString();
}

QIcon QProperty::valueIcon()
{
    return QIcon();
}

bool    QProperty::enabled()
{
    return m_enabled;
}

bool QProperty::modified()
{
    return m_modified;
}

QVariant QProperty::value()
{
    return m_value;
}

void QProperty::valueChanged()
{
    if(m_parent!=NULL)
    {
        m_parent->valueChanged();
    }
    else
    {
        emit changed();
        emit changed(m_name);
    }
}

QProperty* QProperty::parent()
{
    return m_parent;
}

void QProperty::setDefaultValue(QVariant value)
{
    m_defaultValue=value;
    emit changed(m_name);
}

QVariant QProperty::defaultValue()
{
    return m_defaultValue;
}

bool QProperty::reset()
{
    return m_reset;
}

void QProperty::setReset(bool reset)
{
    m_reset=reset;
}

void QProperty::setGroup(const QString &group)
{
    m_group=group;
}

QString QProperty::group()
{
    return m_group;
}

void QProperty::setObject(QObject *obj)
{
    m_object=obj;
    if(m_object->metaObject()->className()!=QString("QFormWidget"))
    {
        connect(this,SIGNAL(changed(QString)),m_object,SLOT(updateProperty(QString)));
    }
}

QObject* QProperty::object()
{
    return m_object;
}

bool QProperty::needSave()
{
    return m_needSave;
}

void QProperty::setNeedSave(bool save)
{
    m_needSave=save;
}

void QProperty::setCore(AbstractCore *core)
{
    m_core=core;
}

AbstractCore *QProperty::core()
{
    return m_core;
}


XMLProperty *QProperty::xmlProperty()
{
    return m_xmlProperty;
}

void QProperty::setAttribute(const QString &key, const QVariant &value)
{
    if(key=="")
    {
        return;
    }
    int index=key.indexOf("::");
    QString n;
    if(index>=0)
    {
        n=key.left(index);
        if(n!="")
        {
            foreach(QProperty *c,m_children)
            {
                if(c->name()==n)
                {
                    c->setAttribute(key.mid(index+2),value);
                    return;
                }
            }
        }
    }
    QVariant v=m_attributes.value(key);
    if(v!=value)
    {
        if(key=="enabled")
        {
            setEnabled(value.toBool());
        }
        m_attributes.insert(key,value);
        emitAttributeChanged();
    }
}

void QProperty::emitAttributeChanged()
{
    if(m_parent!=NULL)
    {
        m_parent->emitAttributeChanged();
    }
    else
    {
        emit attributeChanged();
    }
}

QVariant QProperty::attribute(const QString &key, const QVariant def)
{
    return m_attributes.value(key,def);
}


QIntProperty::QIntProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_value=0;
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("number");
}

QFloatProperty::QFloatProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_value=0;
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("float");
}

QBoolProperty::QBoolProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_value=false;
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("bool");
}

QIcon QBoolProperty::valueIcon()
{
    QStyleOptionButton opt;
    opt.state |=m_value.toBool()?QStyle::State_On:QStyle::State_Off;

    opt.state |=QStyle::State_Enabled;

    const QStyle* style=QApplication::style();
    const int indicatiorWidth=style->pixelMetric(QStyle::PM_IndicatorWidth,&opt);
    const int indicatiorHeight=style->pixelMetric(QStyle::PM_IndicatorHeight,&opt);
    const int listViewIconSize=indicatiorWidth;
    const int pixmapWidth=indicatiorWidth;
    const int pixmapHeight=qMax(indicatiorHeight,listViewIconSize);

    opt.rect=QRect(0,0,indicatiorWidth,indicatiorHeight);

    QPixmap pixmap=QPixmap(pixmapWidth,pixmapHeight);

    pixmap.fill(Qt::transparent);

    {
        const int xoff=(pixmapWidth>indicatiorWidth)?(pixmapWidth-indicatiorWidth)/2:0;
        const int yoff=(pixmapHeight>indicatiorHeight)?(pixmapHeight-indicatiorHeight)/2:0;
        QPainter p(&pixmap);
        p.translate(xoff,yoff);
        style->drawPrimitive(QStyle::PE_IndicatorCheckBox,&opt,&p);
    }
    return QIcon(pixmap);
}

QByteProperty::QByteProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_value="";
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("string");
}

QSizeProperty::QSizeProperty(const QString &name,QProperty *parent):
    QProperty(name,parent)
{
    m_value=QSize(0,0);
    m_widthProperty=new QIntProperty("Width",this);
    m_heightProperty=new QIntProperty("Height",this);
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("size");
}

QString QSizeProperty::valueText()
{
    QSize sz=m_value.toSize();
    return QString("[%1 x %2]").arg(sz.width()).arg(sz.height());
}

void QSizeProperty::valueChanged()
{
    QSize sz(m_widthProperty->value().toInt(),m_heightProperty->value().toInt());
    m_value=sz;
    QProperty::valueChanged();
}

void QSizeProperty::setValue(const QVariant &value)
{
    m_widthProperty->setValue(value.toSize().width());
    m_heightProperty->setValue(value.toSize().height());
    QProperty::setValue(value);
}


QRectProperty::QRectProperty(const QString &name,QProperty *parent):
    QProperty(name,parent)
{
    m_value=QRect(0,0,0,0);
    m_xProperty=new QIntProperty("X",this);
    m_yProperty=new QIntProperty("Y",this);
    m_widthProperty=new QIntProperty("Width",this);
    m_heightProperty=new QIntProperty("Height",this);
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("rect");
}

QString QRectProperty::valueText()
{
    QRect re=m_value.toRect();
    return QString("[(%1, %2), %3 x %4]").arg(re.x()).arg(re.y()).arg(re.width()).arg(re.height());
}

void QRectProperty::valueChanged()
{
    QRect re(m_xProperty->value().toInt(),m_yProperty->value().toInt(),m_widthProperty->value().toInt(),m_heightProperty->value().toInt());
    //setValue(QVariant(re));
    m_value=re;
    QProperty::valueChanged();
}

void QRectProperty::setValue(const QVariant &value)
{
    m_xProperty->setValue(value.toRect().x());
    m_yProperty->setValue(value.toRect().y());
    m_widthProperty->setValue(value.toRect().width());
    m_heightProperty->setValue(value.toRect().height());
    QProperty::setValue(value);
}

QFontProperty::QFontProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_family=new QFontFamilyProperty("Family",this);
    m_pointSize=new QIntProperty("Point Size",this);
    m_bold=new QBoolProperty("Bold",this);
    m_italic=new QBoolProperty("Italic",this);
    m_underline=new QBoolProperty("Underline",this);
    m_strikeout=new QBoolProperty("Strikeout",this);
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("font");
}

void QFontProperty::setValue(const QVariant &value)
{
    QFont f=value.value<QFont>();
    m_family->setValue(f.family());
    m_pointSize->setValue(f.pointSize());
    m_bold->setValue(f.bold());
    m_italic->setValue(f.italic());
    m_underline->setValue(f.underline());
    m_strikeout->setValue(f.strikeOut());
    QProperty::setValue(value);
}

void QFontProperty::valueChanged()
{
    if(m_pointSize->value().toInt()<=0)
    {
        return;
    }
    QFont f;
    f=m_value.value<QFont>();
    f.setFamily(m_family->value().toString());
    f.setPointSize(m_pointSize->value().toInt());
    f.setBold(m_bold->value().toBool());
    f.setItalic(m_italic->value().toBool());
    f.setUnderline(m_underline->value().toBool());
    f.setStrikeOut(m_strikeout->value().toBool());

    m_value.setValue<QFont>(f);
    QProperty::valueChanged();
}

QString QFontProperty::valueText()
{
    return QString("[%1,%2]").arg(m_family->value().toString()).arg(m_pointSize->value().toInt());
}

QIcon QFontProperty::valueIcon()
{
    QFont font=m_value.value<QFont>();
    QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
    img.fill(0);
    QPainter p(&img);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::Antialiasing, true);
    font.setPointSize(13);
    p.setFont(font);
    QTextOption t;
    t.setAlignment(Qt::AlignCenter);
    p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t);
    return QPixmap::fromImage(img);
}

QString QEnumProperty::valueText()
{
    return m_object->metaObject()->property(m_object->metaObject()->indexOfProperty(m_name.toLocal8Bit())).enumerator().valueToKey(m_value.toInt());
}

QEnumProperty::QEnumProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_value="";
    m_xmlProperty->setValue("");
    m_xmlProperty->setType("number");
}


QCursorProperty::QCursorProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    for(int i=0;i<=Qt::ClosedHandCursor;i++)
    {
        m_text.append("");
        m_icon.append("");
    }
    m_text.replace(Qt::ArrowCursor,"Arrow");
    m_icon.replace(Qt::ArrowCursor,":/images/cursors/arrow.png");
    m_text.replace(Qt::UpArrowCursor,"Up Arrow");
    m_icon.replace(Qt::UpArrowCursor,":/images/cursors/uparrow.png");
    m_text.replace(Qt::CrossCursor,"Cross");
    m_icon.replace(Qt::CrossCursor,":/images/cursors/cross.png");
    m_text.replace(Qt::WaitCursor,"Wait");
    m_icon.replace(Qt::WaitCursor,":/images/cursors/wait.png");
    m_text.replace(Qt::IBeamCursor,"IBeam");
    m_icon.replace(Qt::IBeamCursor,":/images/cursors/ibeam.png");
    m_text.replace(Qt::SizeVerCursor,"Size Vertical");
    m_icon.replace(Qt::SizeVerCursor,":/images/cursors/sizev.png");
    m_text.replace(Qt::SizeHorCursor,"Size Horizontal");
    m_icon.replace(Qt::SizeHorCursor,":/images/cursors/sizeh.png");
    m_text.replace(Qt::SizeFDiagCursor,"Size Backslash");
    m_icon.replace(Qt::SizeFDiagCursor,":/images/cursors/sizef.png");
    m_text.replace(Qt::SizeBDiagCursor,"Size Slash");
    m_icon.replace(Qt::SizeBDiagCursor,":/images/cursors/sizeb.png");
    m_text.replace(Qt::SizeAllCursor,"Size All");
    m_icon.replace(Qt::SizeAllCursor,":/images/cursors/sizeall.png");
    m_text.replace(Qt::BlankCursor,"Blank");
    m_icon.replace(Qt::BlankCursor,"");
    m_text.replace(Qt::SplitVCursor,"Split Vertical");
    m_icon.replace(Qt::SplitVCursor,":/images/cursors/vsplit.png");
    m_text.replace(Qt::SplitHCursor,"Split Horizontal");
    m_icon.replace(Qt::SplitHCursor,":/images/cursors/hsplit.png");
    m_text.replace(Qt::PointingHandCursor,"Pointing Hand");
    m_icon.replace(Qt::PointingHandCursor,":/images/cursors/hand.png");
    m_text.replace(Qt::ForbiddenCursor,"Forbidden");
    m_icon.replace(Qt::ForbiddenCursor,":/images/cursors/no.png");
    m_text.replace(Qt::OpenHandCursor,"Open Hand");
    m_icon.replace(Qt::OpenHandCursor,":/images/cursors/openhand.png");
    m_text.replace(Qt::ClosedHandCursor,"Closed Hand");
    m_icon.replace(Qt::ClosedHandCursor,":/images/cursors/closedhand.png");
    m_text.replace(Qt::WhatsThisCursor,"What's This");
    m_icon.replace(Qt::WhatsThisCursor,":/images/cursors/whatsthis.png");
    m_text.replace(Qt::BusyCursor,"Busy");
    m_icon.replace(Qt::BusyCursor,":/images/cursors/busy.png");

    m_xmlProperty->setValue(0);
    m_xmlProperty->setType("number");
}

QString QCursorProperty::valueText()
{
    QCursor c=m_value.value<QCursor>();
    return m_text.at(c.shape());
}

QIcon   QCursorProperty::valueIcon()
{
    QCursor c=m_value.value<QCursor>();
    return QIcon(m_icon.at(c.shape()));
}

QStringList QCursorProperty::textList()
{
    return m_text;
}

QStringList QCursorProperty::iconList()
{
    return m_icon;
}

void QCursorProperty::setValue(const QVariant &value)
{
    if(m_value!=value)
    {
        m_value=value;
        m_xmlProperty->setValue(m_value.value<QCursor>().shape());
        valueChanged();
    }
}


QComboItemsProperty::QComboItemsProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("ComboBox_items");
}

QString QComboItemsProperty::valueText()
{
    ComboItems items=m_value.value<ComboItems>();

    return QString("Item Count: %1").arg(items.size());
}


QTimeProperty::QTimeProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("time");
}

QString QTimeProperty::valueText()
{
    QTime ti=m_value.toTime();
    return ti.toString();
}



QDateProperty::QDateProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("date");
}

QString QDateProperty::valueText()
{
    QDate dt=m_value.toDate();
    return dt.toString(Qt::LocalDate);
}


QDateTimeProperty::QDateTimeProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("datetime");
}

QString QDateTimeProperty::valueText()
{
    QDateTime dt=m_value.toDateTime();
    return dt.toString(Qt::LocalDate);
}

QColorProperty::QColorProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("color");
}

QString QColorProperty::valueText()
{
    tagColorInfo c=m_value.value<tagColorInfo>();
    if(c.m_type==0)
    {
        return "None";
    }
    else
    {
        return QString("[%1,%2,%3,%4]").arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
    }
}

QIcon QColorProperty::valueIcon()
{
    tagColorInfo c=m_value.value<tagColorInfo>();
    if(c.m_type==0)
    {
        return QIcon();
    }
    else
    {
        QPixmap pixmap=QPixmap(16,16);

        pixmap.fill(c.m_color);
        return QIcon(pixmap);
    }
}

QBorderProperty::QBorderProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("border");
}

QString QBorderProperty::valueText()
{
    tagBorderInfo c=m_value.value<tagBorderInfo>();
    if(c.m_isNull)
    {
        return "None";
    }
    else
    {
        return QString("[%1,%2]").arg(c.m_border_type).arg(c.m_border_width);
    }
}

QIcon QBorderProperty::valueIcon()
{
    tagBorderInfo c=m_value.value<tagBorderInfo>();
    if(c.m_isNull)
    {
        return QIcon();
    }
    else
    {
        QPixmap pixmap=QPixmap(16,16);

        pixmap.fill(c.m_color);
        return QIcon(pixmap);
    }
}

QImageProperty::QImageProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("image");
}

QString QImageProperty::valueText()
{
    tagImageInfo info=m_value.value<tagImageInfo>();
    QString name;
    int index=info.m_name.lastIndexOf("/");
    name=info.m_name.mid(index+1);
    if(name=="")
    {
        return "None";
    }
    else
    {
        return QString("%1[%2,%3,%4,%5]").arg(name).arg(info.m_left).arg(info.m_top)
                .arg(info.m_right).arg(info.m_bottom);
    }
}

void QImageProperty::setValue(const QVariant &value)
{
    m_xmlProperty->setValue(m_value);
    if(m_value!=value)
    {
        m_value=value;
        tagImageInfo info=m_value.value<tagImageInfo>();
        QProject::project()->insertResource(info.m_name,m_object,m_name);
        valueChanged();
    }
}

QIcon QImageProperty::valueIcon()
{
    tagImageInfo info=m_value.value<tagImageInfo>();
    QByteArray array=QProject::project()->getResource(info.m_name).m_data;
    if(array.size()!=0)
    {
        QPixmap p=QPixmap(16,16);
        p.loadFromData(array);
        return QIcon(p);
    }
    else
    {
        return QIcon();
    }
}

QMemeryValueProperty::QMemeryValueProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("memeryValue_items");
}

QString QMemeryValueProperty::valueText()
{
    MemeryValueItems c=m_value.value<MemeryValueItems>();
    if(c.size()==0)
    {
        return "None";
    }
    else
    {
        return QString("count:%1").arg(c.size());
    }
}

QScriptProperty::QScriptProperty(const QString &name, QProperty *parent):
    QByteProperty(name,parent)
{

}

QString QScriptProperty::valueText()
{
    QString str=m_value.toString();
    str=str.replace("\n","");
    str=str.replace("\r","");
    return str;
}

QPaddingProperty::QPaddingProperty(const QString &name, QProperty *parent):
    QProperty(name,parent)
{
    m_xmlProperty->setValue(m_value);
    m_xmlProperty->setType("padding");
}

QString QPaddingProperty::valueText()
{
    tagPaddingInfo padding=m_value.value<tagPaddingInfo>();
    return QString("[%1 %2 %3 %4]").arg(padding.m_left).arg(padding.m_top).arg(padding.m_right).arg(padding.m_bottom);
}
